#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/moduleparam.h>
#include "include/mymodule.h"
#include <asm-i386/uaccess.h>
#include "include/mymodule2.h"
#include "include/errno.h"

int selected_call;
struct task_struct* selected_process;
struct cdev* my_cdev;
int pidop;
int open=0;
dev_t disp;


MODULE_LICENSE("GPL");
/*
* Inicialització del modul.
*/
static int __init Mymodule_init(void)
{
    int registro;
    
   /* Codi d’inicialització */
   printk(KERN_DEBUG "Mymodule2 cargado con exito\n");

  //creamos el dispositivo con estructura dev_t
  disp = MKDEV(MA,MI);
  
  // Lo registramos
   registro =register_chrdev_region (disp, 1, "modulo2");
   if( registro <0){
   return -1; // error  al registrar el dipositivo
   }
 
   // Reservamos el espacio
   my_cdev=cdev_alloc();

   // Le asociamos las funciones del dispositivo
   my_cdev->owner=THIS_MODULE;
   my_cdev->ops=&mymod_fops;

   // Añadimos las estrcutura a los dispositivos
   registro=cdev_add(my_cdev,disp,1);
if(registro<0){
   return -1; // error al registrar el dipositivo
   }

   return 0;
   // Aquesta funció retorna 0 si tot ha
   // anat correctament i < 0 en cas d’error
}
/*
* Descarrega el módul.
*/

static void __exit Mymodule_exit(void)           
{
/* Codi de finalització */
// Quitamos el registro del dispositivo del sistema
unregister_chrdev_region(disp,1);
printk(KERN_DEBUG "Mymodule2 descargado con exito\n");
}


int mymod_open(struct inode *i, struct file *f)
{

if(current->uid  != 0){ // solo el proceso root puede abrir
	return -EPERM;
}
else if(open==1){ // solo se puede hacer un único open
	return -EBUSY;
}
open=1;
pidop=current->pid;
selected_process=(struct task_struct*)current; // selected_process= proceso actual;
selected_call=0;  // selected_call=open

return 0;
}

ssize_t mymod_read (struct file *f, char __user* buffer, size_t s, loff_t* off){
struct my_thread_info* inf;
int tam;

inf = (struct my_thread_info*)selected_process->thread_info;
tam = s;

if(s > sizeof(struct t_info)){
tam = sizeof(struct t_info);
}


return (ssize_t) copy_to_user(buffer,&inf->estadistiques.est[selected_call].num_entrades,tam);
}

int mymod_ioctl(struct inode *i, struct file *f, unsigned int arg1,unsigned long arg2)
{
int* var2=(int*)(arg2);
int val=(int)arg2;

if(arg1 ==0){ // Canvi de procés 
	
        if(*var2<0){
		return -1;  // Si el pid del proceso no es correcto
	}
	selected_process=find_task_by_pid(*var2);
        if(selected_process==NULL){ // Si el proceso referido en arg2 no existe
		selected_process=find_task_by_pid(pidop);
		return -1;
	}
}
else if(arg1==1){ // Cambio de llamada que tenemos monitorizada
	selected_call=(int)arg2;
}
else if(arg1==2){ // resetear los valores de las estadisticas del proceso monitorizado
	reset_info(selected_process->pid);
}
else if(arg1==3){ // reseteamos los valores de estadisticas de todos los procesos
	reset_all();
}
else if(arg1==4){ // Activamos la monitorizacion
	if((val)<-1 || (val)>4){
		return -1; // No existe esa llamada a sistema para monitorizar
	}
	else{
		activar_monitorizacion(arg2);
	}
}
else if(arg1==5){ // Desactivamos la monitorizacion

	if((val)<-1 || (val)>4){
		return -1; // No existe esa llamada a sistema para monitorizar
	}
	else{
		desactivar_monitorizacion(arg2);
	}
}
else{return -ENOSYS;} // Funcion no implementada


return 0;
}

int mymod_release (struct inode *i, struct file *f) // Liberamos el dispositivo
{
// Eliminamos la estructura
cdev_del(my_cdev);
open=0; // cerramos la monitorización

return 0;
}

int reset_all()
{
struct task_struct* pr;
for_each_process(pr){
	reset_info(pr->pid);
}
return 0;
}


module_init(Mymodule_init);
module_exit(Mymodule_exit);

